package com.example.audiocollection

import android.Manifest
import android.content.pm.PackageManager
import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.media.AudioFormat
import android.media.AudioRecord
import android.media.MediaRecorder
import android.os.Bundle
import android.os.Environment
import android.os.SystemClock
import android.util.Log
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import java.io.File
import java.io.FileOutputStream
import kotlin.system.exitProcess

/** 音频输入源 */
private const val DEFAULT_AUDIO_SOURCE = MediaRecorder.AudioSource.MIC

/** 采样率 */
private const val DEFAULT_SAMPLE_RATE = 44100

/** 声道模式 */
private const val DEFAULT_CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_STEREO

/** 采样位数 */
private const val DEFAULT_AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT

/** 请求权限码 */
private const val REQUEST_PERMISSION_CODE = 1

/** tag */
private const val TAG = "AudioCollection"

/**
 * @author just1296
 * @since 2021-10-21
 */
class MainActivity : AppCompatActivity() {

    /** 开始/停止录音按钮 */
    private val collectionBtn: Button by lazy(LazyThreadSafetyMode.NONE) { findViewById(R.id.collection_btn) }

    /** 录音器 */
    private var audioRecord: AudioRecord? = null

    /** 音频缓冲区大小 */
    private var audioBufferSize: Int = 0

    /** 读取音频数据的线程 */
    private var readerThread: Thread? = null

    /** 文件输出流 */
    private var fileOutputStream: FileOutputStream? = null

    /** 是否已经开始录音 */
    private var startedCollection: Boolean = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        collectionBtn.setOnClickListener {
            if (startedCollection) {
                stopCollection()
            } else {
                startCollection()
            }
        }
    }

    /**
     * 开始录音
     */
    private fun startCollection() {
        val permissions = arrayOf(Manifest.permission.RECORD_AUDIO, Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.READ_EXTERNAL_STORAGE)
        for (permission in permissions) {
            if (ActivityCompat.checkSelfPermission(this, permission) != PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this, permissions, REQUEST_PERMISSION_CODE)
                return
            }
        }
        audioBufferSize = AudioRecord.getMinBufferSize(DEFAULT_SAMPLE_RATE, DEFAULT_CHANNEL_CONFIG,
                DEFAULT_AUDIO_FORMAT)
        if (audioBufferSize == AudioRecord.ERROR_BAD_VALUE) {
            Log.e(TAG, "Invalid parameter")
            return
        }
        Log.d(TAG, "start audio collection")
        if (audioRecord == null) {
            audioRecord = AudioRecord(DEFAULT_AUDIO_SOURCE,
                    DEFAULT_SAMPLE_RATE,
                    DEFAULT_CHANNEL_CONFIG,
                    DEFAULT_AUDIO_FORMAT,
                    audioBufferSize)
        }
        audioRecord?.startRecording()
        readerThread = Thread(AudioReader())
        readerThread?.start()
        startedCollection = true
        collectionBtn.text = getString(R.string.stop_collection)
    }

    /**
     * 停止录音
     */
    private fun stopCollection() {
        try {
            Log.d(TAG, "stop audio collection")
            readerThread?.interrupt()
            audioRecord?.stop()
        } catch (e: Exception) {
            Log.e(TAG, e.message.toString())
        } finally {
            audioRecord?.release()
            audioRecord = null
            startedCollection = false
        }
        collectionBtn.text = getString(R.string.start_collection)
    }

    /**
     * 音频读取器
     */
    private inner class AudioReader: Runnable {

        override fun run() {
            while (startedCollection) {
                val buffer = ByteArray(audioBufferSize)
                when (val ret = audioRecord?.read(buffer, 0, buffer.size)) {
                    AudioRecord.ERROR_INVALID_OPERATION -> {
                        Log.e(TAG, "Error Occurs：ERROR_INVALID_OPERATION")
                    }
                    AudioRecord.ERROR_BAD_VALUE -> {
                        Log.e(TAG, "Error Occurs：ERROR_BAD_VALUE")
                    }
                    else -> {
                        saveAudioFile(buffer)
                        Log.d(TAG, "OK, Read $ret bytes")
                    }
                }
                SystemClock.sleep(10)
            }
            closeFOS()
        }

        /**
         * 保存音频文件
         *
         * @param byteArray 字节数组
         */
        private fun saveAudioFile(byteArray: ByteArray) {
            if (fileOutputStream == null) {
                val filePath = Environment.getExternalStorageDirectory().absolutePath.plus("/test.pcm")
                val file = File(filePath)
                if (!file.exists()) {
                    file.createNewFile()
                }
                fileOutputStream = FileOutputStream(filePath)
            }
            fileOutputStream?.write(byteArray)
        }

        /**
         * 关闭文件流
         */
        private fun closeFOS() {
            try {
                fileOutputStream?.close()
                fileOutputStream = null
            } catch (e: Exception) {
                Log.e(TAG, e.message.toString())
            }
        }
    }

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode == REQUEST_PERMISSION_CODE) {
            for (result in grantResults) {
                if (result != PackageManager.PERMISSION_GRANTED) {
                    exitProcess(0)
                }
            }
            startCollection()
        }
    }
}